package com.jt.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component // 将给类叫给Spring容器管理
@Aspect// 标识该类是一个切面
public class SpringAop {
    /**
     * AOP 利用动态代理扩展目标方法
     * 切面 = 切入点表达式 + 通知方法
     * 切入点表达式：如果对象满足切入点表达式的判断，则spring自动为其创建代理对象
     * 通知方法：目标方法进行扩展的封装方法。
     * 目标对象的bean的ID：userServiceImpl
     * 切入点表达式：
     * 1.bean("bean的id")
     */
    // @Pointcut("within(com.jt.servic.*)")
    // @Pointcut("bean(userServiceImpl)")
    // 匹配方法名和参数类型
    // @Pointcut("execution(* com.jt.servic.UserService.addUser())")
    @Pointcut("@annotation(com.jt.anno.Hxwang)")
    public void pointcut() {
    }


    // 前置通知：在目标方法前执行
    @Before("pointcut()")
    // 方法名就是这样写的
    public void before(JoinPoint joinPoint) {
        Class<?> aClass = joinPoint.getTarget().getClass();
        String name = joinPoint.getSignature().getName();
        String name1 = joinPoint.getSignature().getDeclaringTypeName();
        Object[] args = joinPoint.getArgs();
        System.out.println("我是前置通知！！！");
        System.out.println(aClass);
        System.out.println(name);
        System.out.println(name1);
        System.out.println(Arrays.toString(args));
    }

    // 后置通知  需求： 通过 returning="result" 属性，获取目标方法的返回值，
    // 当做参数传递给result，再返回给用户
    @AfterReturning(value = "pointcut()",returning = "result")
    public void afterReturn(Object result) {
        System.out.println(result);
        System.out.println("我是后置方法！！！");
    }

    // 异常通知
    @AfterThrowing("pointcut()")
    public void afterThrow() {
        System.out.println("我是异常通知");
    }

    // 环绕通知
    @Around("@annotation(com.jt.anno.Hxwang)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前执行");
        // 底层调用动态代理的invoke方法，执行目标方法
        Object object = joinPoint.proceed();
        System.out.println("环绕后执行");
        return object;
    }

}
